/*
Copyright (c) 2022 Huawei Device Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import HuffmanTablesDescriptor from './HuffmanTablesDescriptor';
import HuffmanTable from './HuffmanTable';
import Directory from '../Directory'
import LogUtil from '../../tools/LogUtils';

const TAG: string = "HuffmanTablesDirectory";

class HuffmanTablesDirectory extends Directory {
  public static readonly TAG_NUMBER_OF_TABLES: number = 1;
  static readonly TYPICAL_LUMINANCE_DC_LENGTHS: Int8Array = new Int8Array(
    [0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) ;
  static readonly TYPICAL_LUMINANCE_DC_VALUES: Int8Array= new Int8Array(
    [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B]);
  static readonly TYPICAL_CHROMINANCE_DC_LENGTHS: Int8Array = new Int8Array(
    [0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00]
  );
  static readonly TYPICAL_CHROMINANCE_DC_VALUES: Int8Array = new Int8Array(
    [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B]
  );
  static readonly TYPICAL_LUMINANCE_AC_LENGTHS: Int8Array = new Int8Array(
    [0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
    0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D]
  );
  static readonly TYPICAL_LUMINANCE_AC_VALUES: Int8Array = new Int8Array(
    [0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
    0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
    0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08,
    0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0,
    0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16,
    0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28,
    0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
    0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
    0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
    0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
    0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
    0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
    0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
    0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
    0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
    0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5,
    0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4,
    0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2,
    0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
    0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
    0xF9, 0xFA]
  );
  static readonly TYPICAL_CHROMINANCE_AC_LENGTHS: Int8Array = new Int8Array(
    [0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
    0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77]
  );
  static readonly TYPICAL_CHROMINANCE_AC_VALUES: Int8Array = new Int8Array(
    [0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
    0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
    0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
    0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0,
    0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34,
    0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26,
    0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38,
    0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
    0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
    0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
    0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
    0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96,
    0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5,
    0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4,
    0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3,
    0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2,
    0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
    0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9,
    0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
    0xF9, 0xFA]
  );
  protected readonly tables: HuffmanTable[] = new Array<HuffmanTable>();
  private static readonly _tagNameMap: Map<number, string> = new Map([
    [HuffmanTablesDirectory.TAG_NUMBER_OF_TABLES, "Number of Tables"]
  ]);

  constructor() {
    super();
    this.setDescriptor(new HuffmanTablesDescriptor(this));
  }

  public getName(): string
  {
    return "Huffman";
  }

  public getTagNameMap(): Map<number, string>
  {
    return HuffmanTablesDirectory._tagNameMap;
  }

  public getTable(tableNumber: number): HuffmanTable
  {
    return this.tables[tableNumber];
  }

  public getNumberOfTables(): number
  {
    return this.getInt(HuffmanTablesDirectory.TAG_NUMBER_OF_TABLES);
  }

  public getTables(): Array<HuffmanTable>
  {
    return this.tables;
  }

  public isTypical(): boolean
  {
    LogUtil.debug(TAG, "isTypical start, Checking if Huffman tables are typical.");
    if (this.tables.length == 0) {
      LogUtil.error(TAG, "isTypical end, No Huffman tables found.");
      return false;
    }
    for (let table of this.tables) {
      if (!table.isTypical()) {
        LogUtil.debug(TAG, "isTypical end, Huffman tables are not typical.");
        return false;
      }
    }
    LogUtil.debug(TAG, "isTypical end, Huffman tables are typical.");
    return true;
  }

  public isOptimized(): boolean
  {
    return!this.isTypical();
  }
}

export default HuffmanTablesDirectory